--[=[
 百人牛牛规则
牌型
52张牌无大小王
1、无牛：没有任意三张牌能加起来成为10的倍数。（注：JQK花牌）
2、有牛：从牛1到牛9，任意三张牌相加是10的倍数，剩余2张牌相加不是10的倍数，相加后取个位数，个位数是几（1-9），就是牛几（1-9）。
3、牛牛：任意三张牌相加是10的倍数，剩余2张牌相加也是10的倍数。
4、四炸：即5张牌中有4张一样的牌，此时无需有牛。
5、五花牛：五花牛的花指的是手上的5张牌全为JQK的特殊牛牛牌型。
6、五小牛 牌类游戏牛牛中五张牌均小于5点，总和小于10点，是牛牛里最大的牌。
牌型比较：
1、单张大小：从大到小为K、Q、J、10、9、8、7、6、5、4、3、2、A。
2、花色大小：从大到小为黑桃、红桃、梅花、方片。
3、牌型大小：从大到小 五花牛、四炸、牛牛、有牛（从牛9到牛1）、没牛。
4、庄闲同牌型时，挑出最大的一张牌进行大小比较，若两方最大牌一样，那么花色进行比较。（特例：四炸时比较四张一样的那张牌）
基本规则
1、分庄家和闲家进行游戏。每个闲家分别和庄家比牌。
2、玩家可以主动上庄，成为本回合的庄家。每回合结束后可重新上庄。
3、玩家可以在四个闲家位置上任意下注。
赔率
低倍场房间：
1、无牛到牛六： 1倍。
2、牛七、牛八、牛九： 2倍。
3、牛牛： 3倍。
4、四炸： 4倍。
5、五花牛： 5倍。
6、五小牛：6倍

]=]

local skynet = require "skynet"
-- require "util"

local random = math.random
local tableCopy = table.copy

local Rule = class("Rule")
function  Rule:ctor()
	--随机种子
	math.randomseed()
	self.card = {--扑克牌说明，0xAB, (A为花色 0黑桃 1红心 2草花 3方块)，B为点数1-13为A-K 
		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
     	0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
     	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
     	0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d
	}
	--牌型权重基值 无牛，有牛，牛牛，炸弹，五花牛，五小牛，
	self.tbWeight = {wn=0x10000,yn=0x20000,nn=0x30000,zn=0x40000,whn=0x50000,wxn=0x60000} 
	self.tbCard = {} --发牌
	self.tbCardType = {
		[0] = '无牛',
		[1] = '牛一',
		[2] = '牛二',
		[3] = '牛三',
		[4] = '牛四',
		[5] = '牛五',
		[6] = '牛六',
		[7] = '牛七',
		[8] = '牛八',
		[9] = '牛九',
		[10] = '牛牛',
		[11] = '炸弹',
		[12] = '五花牛',
		[13] = '五小牛',
	}
end

--洗牌
function Rule:shuffle()	
	for k,v in pairs(self.card) do 
		self.tbCard[k] = v
	end
	table.mix(self.tbCard)
end

--取牌
function Rule:getCard(num)
	local tbRes = {}
	local n = num or 0
	for k,v in pairs(self.tbCard) do 
		if n <= 0 then break end
		if v then 
			n = n-1
			table.insert(tbRes,v)
			self.tbCard[k] = nil
		end
	end
	return tbRes
end

--把牌放到最后
function Rule:pushCard(card)
	table.insert(self.tbCard,card)
end

--5小牛 牌类游戏牛牛中五张牌均小于5点，总和小于10点，是牛牛里最大的牌。
function Rule:isWuxiaoniu(tb)
	local tbRes
	local totalNum = 0
	for k,v in pairs(tb) do 
		if v > 0x05 then 
			return tbRes
		end
		totalNum = totalNum + v
	end
	if totalNum > 10 then 
		return tbRes
	end
	tbRes = {1,2,3,4,5}

	return tbRes
end

--是否炸弹， 4张一样的
function Rule:isZhaniu(tb)
	local j = 0
	local tbr = {}
	local tbRes
	local function compaire(num,tb)
		local j = 0
		if num == tb[3] then
			j = j+1 
			table.insert(tbr,3)
		end
		if num == tb[4] then
			j = j+1 
			table.insert(tbr,4)
		end
		if num== tb[5] then
			j = j+1
			table.insert(tbr,5) 
		end		
		return j
	end
	if tb[1] == tb[2] then --前2张一样
		table.insert(tbr,1)
		table.insert(tbr,2)
		j = compaire(tb[1],tb)
		if j==2 then
			for k,v in pairs(tb) do
				if v~=tb[1] then 
					table.insert(tbr,k)
					break
				end
			end
			tbRes = tbr
		end
	else
		j = 0
		tbr = {}
		table.insert(tbr,1)
		j = compaire(tb[1],tb)
		if j==3 then 
			table.insert(tbr,2)
			tbRes = tbr
		end 
		j = 0
		tbr = {}
		table.insert(tbr,2)
		j = compaire(tb[2],tb)
		if j==3 then
			table.insert(tbr,1)
			tbRes = tbr
		end
	end	
	return tbRes
end

--是否有牛
function Rule:hasNiu(tb)
	local tbRes
	local tbWeight = self.tbWeight --牌型权重基值
	local weight = 0 
	local niuji
	local tbc = {
		{1,2,3 ,4,5},
		{1,2,4 ,3,5},
		{1,3,4 ,2,5},
		{2,3,4 ,1,5},
		{1,2,5 ,3,4},
		{1,3,5 ,2,4},
		{2,3,5 ,1,4},
		{1,4,5 ,2,3},
		{2,4,5 ,1,3},
		{3,4,5 ,1,2},
	}
	local a,b,c,d,e
	local w
	local temp = {}
	for k,v in pairs(tbc) do 
		a = tb[v[1]] & 0x0f
		b = tb[v[2]] & 0x0f
		c = tb[v[3]] & 0x0f
		d = tb[v[4]] & 0x0f
		e = tb[v[5]] & 0x0f
		temp = {}
		for i=1,5 do 
			table.insert(temp,tb[v[i]])
		end
		if a > 10 then a = 10 end
		if b > 10 then b = 10 end
		if c > 10 then c = 10 end
		if d > 10 then d = 10 end
		if e > 10 then e = 10 end
		if (a+b+c)%10 == 0 then --有牛
			if (d+e)%10 == 0 then --牛牛
				weight = tbWeight.nn
				tbRes = temp		
				break
			else
				--0XABCDE,A有牛标志, B牛几，C最大牌花色,D最大牌点数 
				w = tbWeight.yn + (d+e)%10*0x1000
				if weight < w then 
					weight = w
					tbRes = temp	
					niuji = (d+e)%10
					print("__牛几____________",d,e,niuji)		
				end
			end
		else --无牛
			if weight == 0 then 
				weight = tbWeight.wn
				tbRes = tb
			end
		end
	end

	return tbRes,weight
end

--算牛 
function Rule:getNiu(tb)
	self:printCard(tb)
 	local tbWeight = self.tbWeight --牌型权重基值
 	local tbRes = {card={},weight=0} --返回结果
 	local tbCard = {} --返回牌
 	local tbCardNum = {} --牌值列表
	local wuhua_niu = 0 --5花牛计数
	local cardnum = 0 --临时牌值
	local maxCard = 0 --最大牌
	local weight = 0 --权重
	local maxCardWeight = 0 --最大牌权重
	for i=1,5 do		
		cardnum = tb[i] & 0x0f
		if cardnum > 10 then--5花牛每张牌要大于10
			wuhua_niu = wuhua_niu + 1
		end
		table.insert(tbCardNum,cardnum)
		--找到最大的牌
		if (tb[i] & 0x0f) > (maxCard & 0x0f) then 
			maxCard = tb[i]
		elseif (tb[i] & 0x0f) == (maxCard & 0x0f) then
			if (tb[i] & 0xf0) < (maxCard & 0xf0) then--
				maxCard = tb[i]
			end		
		end		
	end
	maxCardWeight = ((0x30-(maxCard & 0xf0))>>4) + ((maxCard&0x0f)<<4)
	-- print("___2222_maxCardWeight__________",maxCardWeight,maxCard,(maxCard & 0xf0),maxCard&0x0f,(0x30-(maxCard & 0xf0)),((0x30-(maxCard & 0xf0))>>4),((maxCard&0x0f)<<4))
	--5小牛
	local wuxiao = self:isWuxiaoniu(tbCardNum)
	if wuxiao then 
		print("__5小牛",wuxiao)
		for k,v in pairs(wuxiao) do 
			tbCard[k] = tb[v]
		end
		weight = tbWeight.wxn + maxCardWeight
		tbRes.card = tbCard
		tbRes.weight = weight
		return tbRes
	end
	--5花牛
	if wuhua_niu == 5 then
		print("__5花牛",wuhua_niu) 
		weight = tbWeight.whn + maxCardWeight
		tbCard = tb
		tbRes.card = tbCard
		tbRes.weight = weight
		return tbRes
	end
	--炸
	local zhaniu = self:isZhaniu(tbCardNum)
	if zhaniu then 
		print("__炸",zhaniu)
		for k,v in pairs(zhaniu) do 
			tbCard[k] = tb[v]
		end
		for i=1,4 do
			--找到最大的牌
			if (tb[i] & 0x0f) > (maxCard & 0x0f) then 
				maxCard = tb[i]
			elseif (tb[i] & 0x0f) == (maxCard & 0x0f) then
				if (tb[i] & 0xf0) < (maxCard & 0xf0) then--
					maxCard = tb[i]
				end		
			end		
		end
		maxCardWeight = ((0x30-(maxCard & 0xf0))>>8) + ((maxCard&0x0f)<<8)		
		weight = tbWeight.zn + maxCardWeight
		tbRes.card = tbCard
		tbRes.weight = weight
		return tbRes
	end
	--牛
	tbCard,weight = self:hasNiu(tb)
	weight = weight + maxCardWeight
	--
	tbRes.card = tbCard
	tbRes.weight = weight
	return tbRes
end

--通过权重取牌型值
function Rule:getCardType(weight)
	local cardType = {"没牛","牛", "牛牛", "炸弹", "五花牛","五小牛"}
	local nj = {"一", "二", "三","四","五","六","七","八","九"}
	local i = (weight&0xf0000)/0x10000
	local text = cardType[i]
	if not text then 
		return "getCardType 错误" ..i
	end
	if i == 2 then 
		local n = (weight&0x0f000)/0x1000
		print("_________________",n)
		text = text .. nj[n]
	end
	local num = 0
	for k,v in pairs(self.tbCardType) do 
		if text == v then 
			num = k
			break
		end
	end
	return num
end

function Rule:getCardTypeText(weight)
	local cardType = {"没牛","牛", "牛牛", "炸弹", "五花牛","五小牛"}
	local nj = {"一", "二", "三","四","五","六","七","八","九"}
	local i = (weight&0xf0000)/0x10000
	local text = cardType[i]
	if not text then 
		return "getCardType 错误" ..i
	end
	if i == 2 then 
		local n = (weight&0x0f000)/0x1000
		print("_______牛__________",n)
		text = text .. nj[n]
	end
	return text
end

--通过权重取最大牌
function Rule:getMaxCard(weight)
	local hua   = {"黑", "红", "梅", "方"}
	local dian = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}
	local we = weight & 0x000ff
	return hua[(we&0x0f) + 1]..dian[we&0xf0]
end

--取倍率 
function Rule:getRate(weight)
	local i = (weight&0xf0000)/0x10000
	if i < 2 then 
		return 1
	end
	if i > 2 then --牛牛x3，炸弹x4，五花牛x5，五小牛x6，
		return i
	end
	if i == 2 then --有牛 <牛7=1倍，>牛7=2倍
		local n = (weight&0x0f000)/0x1000
		print("_________________",n)
		if n < 7 then 
			return 1
		else
			return 2
		end
	end
	return 1
end

--找最大牌型
function Rule:getBestCard( card )
	local tb = table.copy(card)
	local res1 = self:getNiu(tb)
	local res2
	local index
	for k,v in pairs(self.tbCard) do
		tb[5] = v
		res2 = self:getNiu(tb)
		if res2.weight > res1.weight then 
			res1 = res2
			index = k
		end
	end
	if index then 
		self.tbCard[index] = card[5]
		card = res1.card
	end
	return card
end

--找最差牌型
function Rule:getWorstCard(card)
	local tb = table.copy(card)
	local res1 = self:getNiu(tb)
	local res2
	local index
	for k,v in pairs(self.tbCard) do
		tb[5] = v
		res2 = self:getNiu(tb)
		if res2.weight < res1.weight then 
			res1 = res2
			index = k
		end
	end
	if index then 
		self.tbCard[index] = card[5]
		card = res1.card
	end
	return card	
end

--列出所有组合，
function Rule:getBiger(weight)
	local tbCard = {}
	local res
	for k,v in pairs(self.tbCard) do 
		if v then 
			table.insert(tbCard,v)
		end
	end
	self.tbCard = tbCard
	local combin = getCombination(tbCard,5)
	print(self.tbCard,"______________self.tbCard___")
	for _,cards in pairs(combin) do 
		res = self:getNiu(cards)
		if res.weight > weight then 
			for k,v in pairs(self.tbCard) do 
				if v == cards[1] or v == cards[2] or v == cards[3] or v == cards[4] or v == cards[5] then 
					self.tbCard[k] = nil
				end
			end
			return res
		end
	end
	return res
end

--找一个五花牛
function Rule:getBigerWuhua(cards)
	local tbCard = {}
	local res
	local cardnum
	for k,v in pairs(self.tbCard) do 
		if v then 
			cardnum = v & 0x0f
			if cardnum > 10 then--5花牛每张牌要大于10
				table.insert(tbCard,v)
				self.tbCard[k] = nil
			end	
			if #tbCard == 5	then 
				break
			end
		end
	end
	if #tbCard == 5 then 
		--把牌放回去
		for _,v in pairs(cards) do 
			table.insert(self.tbCard,v)
		end
		-- print("____5花牛")
		-- self:printCard(tbCard)
		return tbCard
	end
	return nil
end



--输出16进制牌
function Rule:printCard(cards)
	local str = "___printCard__"
	for k,v in pairs(cards) do 
		str = str..', ' .. string.format("%02x",v)
	end
	print(str)
end
return Rule

